﻿//*************************************************************************************************
// InnerText.cs
// Owner: Herodotos Herodotou (t-herohe)
//
// This class represents the inner text of an html tag. It contains the 
// beginning and ending offset of its location in the whole document.
//
// Copyright(c) Microsoft Corporation, 2008
//*************************************************************************************************

using System.Text;
namespace WebAndLoadTestPluginsAndRules
{
    public class InnerText
    {
        // ****************************************************************************
        // Constructors
        // ****************************************************************************
        public InnerText()
        {
            m_documentContent = null;
            m_beginOffset = -1;
            m_endOffset = -1;
            m_removeInnerTags = false;
            m_collapseWhiteSpace = false;
        }

        public InnerText(string documentContent, int beginOffset,
                         int endOffset, bool removeInnerTags, bool collapseWhiteSpace)
        {
            m_documentContent = documentContent;
            m_beginOffset = beginOffset;
            m_endOffset = endOffset;
            m_removeInnerTags = removeInnerTags;
            m_collapseWhiteSpace = collapseWhiteSpace;
        }


        // ****************************************************************************
        // Public Methods
        // ****************************************************************************

        /// <summary>
        /// Returns a string containing the inner text represented by this object
        /// </summary>
        public string Value
        {
            get
            {
                // Some error checking
                if (m_beginOffset < 0 ||
                    m_beginOffset > m_endOffset ||
                    m_documentContent == null ||
                    m_endOffset > m_documentContent.Length)
                {
                    return null;
                }

                // Get the inner text
                if (m_removeInnerTags)
                {
                    return RemoveHtmlTags();
                }
                else if (m_collapseWhiteSpace)
                {
                    return CollapseAllWhiteSpace();
                }
                else
                {
                    return m_documentContent.Substring(m_beginOffset,
                        m_endOffset - m_beginOffset + 1);
                }
            }
        }

        /// <summary>
        /// Returns the entire document
        /// </summary>
        public string DocumentContent
        {
            get
            {
                return m_documentContent;
            }
        }

        /// <summary>
        /// Returns the begin offset of the inner text's location
        /// </summary>
        public int BeginOffset
        {
            get
            {
                return m_beginOffset;
            }
        }

        /// <summary>
        /// Returns the end offset of the inner text's location
        /// </summary>
        public int EndOffset
        {
            get
            {
                return m_endOffset;
            }
        }

        /// <summary>
        /// Used to specify whether inner tags withing the inner text should be 
        /// filtered out or not
        /// </summary>
        public bool RemoveInnerTags
        {
            get
            {
                return m_removeInnerTags;
            }

            set
            {
                m_removeInnerTags = value;
            }
        }

        /// <summary>
        /// Used to specify whether extra white space should be collapsed or not.
        /// </summary>
        public bool CollapseWhiteSpace
        {
            get
            {
                return m_collapseWhiteSpace;
            }

            set
            {
                m_collapseWhiteSpace = value;
            }
        }


        // ****************************************************************************
        // Private Methods
        // ****************************************************************************

        /// <summary>
        /// Removes all the html tags located within the inner text
        /// </summary>
        /// <returns>The inner text without any inner tags</returns>
        private string RemoveHtmlTags()
        {
            StringBuilder result = new StringBuilder();
            bool withinTag = false;
            bool ignoreWhiteSpace = false;
            char ch;

            for (int i = m_beginOffset; i <= m_endOffset; ++i)
            {
                ch = m_documentContent[i];
                if (!withinTag && ch != '<')
                {
                    if (m_collapseWhiteSpace)
                    {
                        if (!IsWhiteSpace(ch))
                        {
                            result.Append(ch);
                            ignoreWhiteSpace = false;
                        }
                        else if (ignoreWhiteSpace == false)
                        {
                            result.Append(' ');
                            ignoreWhiteSpace = true;
                        }
                    }
                    else
                    {
                        result.Append(ch);
                    }
                }
                else if (!withinTag && ch == '<')
                {
                    withinTag = true;
                }
                else if (withinTag && ch == '>')
                {
                    withinTag = false;
                }
            }

            if (m_collapseWhiteSpace)
            {
                return result.ToString().Trim();
            }
            else
            {
                return result.ToString();
            }
        }

        /// <summary>
        /// Collapses all whitespace (including new lines and tabs) into a single space
        /// </summary>
        /// <returns>The inner text with all whitespace collapsed</returns>
        private string CollapseAllWhiteSpace()
        {
            StringBuilder result = new StringBuilder();
            bool ignoreWhiteSpace = false;
            char ch;

            for (int i = m_beginOffset; i <= m_endOffset; ++i)
            {
                ch = m_documentContent[i];
                if (!IsWhiteSpace(ch))
                {
                    result.Append(ch);
                    ignoreWhiteSpace = false;
                }
                else if (ignoreWhiteSpace == false)
                {
                    result.Append(' ');
                    ignoreWhiteSpace = true;
                }
            }

            return result.ToString().Trim();
        }

        /// <summary>
        /// Determine if the specified character is whitespace or not.
        /// </summary>
        /// <param name="ch">A character to check</param>
        /// <returns>True if the character is whitespace</returns>
        private bool IsWhiteSpace(char ch)
        {
            return ("\t\n\r ".IndexOf(ch) != -1);
        }


        // ****************************************************************************
        // Private Members
        // ****************************************************************************

        private string m_documentContent;
        private int m_beginOffset;
        private int m_endOffset;
        private bool m_removeInnerTags;
        private bool m_collapseWhiteSpace;
    }
}
